\section*{Другие RIBы}

 Отметим, что у RIBов бывает не только текстовое, но
    и бинарное (оптимизированное для быстрой загрузки рендерером) и
    упакованное (оптимизированное для уменьшения занимаемого дискового
    пространства – используется библиотека упаковки GZIP)
    представление. Объединённого бинарно-упакованного представления
    нет, но его несложно сымитировать при помощи той же самой командной
    строки:
  
\begin{lstlisting}[frame=single, framerule=0pt, framesep=10pt, xleftmargin=10pt, xrightmargin=10pt, basicstyle=\ttfamily \small, backgroundcolor=\color{light-gray}]
catrib -binary test2.rib | gzip -cq9 > test2.gbin
\end{lstlisting}

 Слева направо: программа catrib (из поставки Pixar
    Renderman Pro Server) переводит файл test2.rib в бинарный формат и
    результат передаёт в программу gzip (вам придётся скачать её из
    Интернета), которая упаковывает её и передаёт дальше, в файл
    test2.gbin.
  

 Чтобы теперь отрендерить файл test2.gbin, развернём
    цепочку программ в другом направлении:
  
\begin{lstlisting}[frame=single, framerule=0pt, framesep=10pt, xleftmargin=10pt, xrightmargin=10pt, basicstyle=\ttfamily \small, backgroundcolor=\color{light-gray}]
gzip -cd test2.gbin | prman
\end{lstlisting}
  

 Что и требовалось доказать.
  

 Для
    продвинутых: Я вам по секрету скажу
    – на самом деле можно делать и так:
  
\begin{lstlisting}[frame=single, framerule=0pt, framesep=10pt, xleftmargin=10pt, xrightmargin=10pt, basicstyle=\ttfamily \small, backgroundcolor=\color{light-gray}]
prman test2.gbin
\end{lstlisting}
  

 Prman, а
    также некоторые другие рендереры, понимают такие файлы и отлично с
    ними работают.

  \section*{shader.exe}

 Вернёмся к нашему шарику. Переименовываем файл в
    test3.rib и вносим небольшие изменения – убираем строку,
    определяющую материал (Surface “plastic”):
  
\code{code/rib_example/test3.rib}


 Различия в файле минимальны, но зато какое различие
    в результате:
  

 \gr{image045}
  

 В отличие от некоторых других рендереров, у prman
    есть понятие “шейдера по умолчанию” (этот шейдер хранится в файле с
    характерным названием defaultsurface.sl; у
    некоторых рендереров этот материал встроен в код рендерера –
    “захардкожен”; аналогом из мира Mayaявляется
    lambert1, назначаемый на все вновь создаваемые объекты). Даже если
    вы не назначили материал на свою геометрию, она всё равно
    отрендерится с использованием материала по умолчанию.
  

 Для
    продвинутых: в лучших FX-домах
    иногда в качестве шейдера по умолчанию устанавливают закраску
    модели красным цветом. Таким образом, при первом же тестовом
    рендеринге будет сразу видно, на какую из моделей вы забыли
    наложить материалы. Если геометрии в сцене действительно много – подобный
    трюк будет очень полезен.
  

 Ранее в своих экспериментах мы использовали шейдеры
    Plastic и Stone. Вообще говоря, согласно спецификации стандарта, со
    всеми Renderman-совместимыми рендерерами должны поставляться
    следующие шейдеры (вы помните, что источники света в Renderman тоже
    определяются шейдерами):
  
\begin{itemize}
	\item null
	\item constant
	\item      matte
	\item      metal
	\item      shinymetal
	\item      plastic
	\item      paintedplastic
	\item      ambientlight
	\item      distantlight
	\item      pointlight
	\item      spotlight
	\item      depthcue
	\item      fog
	\item      bumpy
	\item      background
\end{itemize}

 Так что поиграться уже есть с чем, но мы хотим
    сделать что-то своё. Представим себе, что вы где-то из Интернета
    скачали шейдер, который обучает вас использованию в Shading
    Language функции noise:
  
\code{code/rib_example/noisetest.sl}

 Для
    продвинутых: Нойз (“шум”) – это
    отличный и обычно первый из приходящих в голову способов добавить
    нерегулярности в “стерильную” компьютерную картинку.
  

 Сохраните его в текстовый файл под названием
    noisetest.sl рядом с файлом test3.rib. Немного правим test3.rib,
    добавляя в него ссылку на новый материал:
  
\code{code/rib_example/test3.rib}

 Запускаем на рендеринг – и получаем сообщение об ошибке:
  
\begin{lstlisting}[frame=single, framerule=0pt, framesep=10pt, xleftmargin=10pt, xrightmargin=10pt, basicstyle=\ttfamily \small, backgroundcolor=\color{light-gray}]
S01001 Cannot load shader "noisetest".  (WARNING)
\end{lstlisting}

 Что происходит? Мы же вроде бы всё правильно
    сделали, указали материал, положили шейдер рядом – что не так? Ан
    нет, не всё так просто. Перед непосредственным использованием
    шейдер необходимо привести в состояние, которое будет максимально
    удобным для рендерера – а попросту говоря,
    откомпилировать.
  

 Для
    любознательных: Конечно же, рендерер
    мог бы и сам понять, чего от него хотят, и откомпилировать шейдер
    внутри себя. Но это бы противоречило духу и одному из основных
    принципов Unix (“для каждой задачи – своя небольшая программа”),
    исторической справедливости и не дало бы  нам в руки могучее оружие
    пайпинга – а оно нам доступно и в этом случае.
  

 Для компиляции используется вторая программа нашего
    могучего триумвирата –
  

 shader.exe. Возможности и гибкость вызова этой
    программы абсолютно аналогичны возможностям и гибкости
    prman.exe  - если мы
    хотим, то можем соорудить цепочку программ, которые будут
    генерировать тексты шейдеров на языке SL. Но мы сделаем
    просто:
  
\begin{lstlisting}[frame=single, framerule=0pt, framesep=10pt, xleftmargin=10pt, xrightmargin=10pt, basicstyle=\ttfamily \small, backgroundcolor=\color{light-gray}]
shader noisetest.sl
\end{lstlisting}

 Программа отработала и в нашей директории рядом с
    файлов noisetest.sl появился noisetest.slo. Не стоит в него
    заглядывать – там интересно, но не настолько, чтобы мы отвлекались.
    Попробуем отрендерить картинку ещё раз и:
  

 \gr{image047}
  

 Для
    продвинутых: Далеко не очевидным,
    особенно для начинающих, является тот факт, что шейдеры вообще
    нужно компилировать. Даже если не затрагивать исторические корни
    языка шейдеров – а именно язык программирования C и модель работы с
    программами, написанными на нём  – достаточно будет одного лишь
    довода в пользу такого требования – скорость исполнения. Язык С
    достаточно сложен для того, чтобы его быстрая его интерпретация
    (выполнение программы без предварительной компиляции) была почти
    невозможной. Поэтому создатели рендереров делают всё возможное,
    чтобы ускорить процесс обработки шейдеров внутри своих программ,
    перенося эту задачу на компиляторы шейдеров. Prman внутри себя
    использует архитектуру выполнения SIMD, для которой компилятором
    shader генерируется специальный бинарный код. Другие рендереры
    поступают по-другому, например, RenderDotC превращает SL-код в
    минипрограмму на языке программирования C++, которая затем
    компилируется уже в файл DLL – и скорость выполнения шейдера таким
    хитрым образом увеличивается во много раз.
  

 Вернёмся к нашему RIBу. Вот строка из него, которая
    определяет новый подключённый материал:
  
\begin{lstlisting}[frame=single, framerule=0pt, framesep=10pt, xleftmargin=10pt, xrightmargin=10pt, basicstyle=\ttfamily \small, backgroundcolor=\color{light-gray}]
Surface  "noisetest"
\end{lstlisting}

 Это строку можно модифицировать, чтобы передать
    шейдеру параметры, например, вот так:

\begin{lstlisting}[frame=single, framerule=0pt, framesep=10pt, xleftmargin=10pt, xrightmargin=10pt, basicstyle=\ttfamily \small, backgroundcolor=\color{light-gray}]
Surface "noisetest" "freq" 100
\end{lstlisting}

 \gr{image049}
  

 Дальше – больше. Поскольку язык SL является
    потомком языка C, то нам доступны такие возможности C, как
    препроцессор и макросы. Проиллюстрируем это на простом примере.
    Немного изменим наш шейдер
  
\code{code/rib_example/noisetest2.sl}  

 и строку вызова его компиляции:
  
\begin{lstlisting}[frame=single, framerule=0pt, framesep=10pt, xleftmargin=10pt, xrightmargin=10pt, basicstyle=\ttfamily \small, backgroundcolor=\color{light-gray}]
shader -DFREQD=2 noisetest.sl
\end{lstlisting}

 Обратите внимание на то, что мы ввели в шейдер
    новую символьную константу (для удобства она обозначена большими
    буквами - FREQD), которую можем переопределять вне шейдера, в
    командной строке компилятора. Результат рендеринга будет,
    естественно, другим (мы вернули строку подключения шейдера в
    исходное состояние):
  

 \gr{image051}
  

 Учтите, что если бы мы вызвали компилятор без этого
    параметра, например, так
  
\begin{lstlisting}[frame=single, framerule=0pt, framesep=10pt, xleftmargin=10pt, xrightmargin=10pt, basicstyle=\ttfamily \small, backgroundcolor=\color{light-gray}]
shader noisetest.sl
\end{lstlisting}

 то получили бы ошибку – ведь константа останется
    неопределённой.
  

 Уже вкусно? Сейчас будет ещё вкуснее. Поскольку в
    наших руках почти что язык C, то мы можем вынести куски кода в
    подключаемые файлы (included files) или, наоборот, использовать уже
    готовые подключаемые файлы в своём шейдере. Один из самых
    интересных для изучения начинающими include-файлов можно найти в
    RManNotes, небольшом онлайновом пособии по Renderman Shading
    Language (его перевод на русский язык доступен на сайте
    Renderman.ru). Мы же воспользуемся стандартными возможностями из
    поставки Renderman Pro Server. Подключаем к нашему шейдеру
    библиотеку материалов:
  
	\code{code/rib_example/noisetest3.sl}  


 и вызываем компиляцию:
  
\begin{lstlisting}[frame=single, framerule=0pt, framesep=10pt, xleftmargin=10pt, xrightmargin=10pt, basicstyle=\ttfamily \small, backgroundcolor=\color{light-gray}]
shader -I%RMANTREE%\lib\shaders -DFREQD=2 noisetest.sl
\end{lstlisting}  

 и рендеринг:
  

 \gr{image053}
  

 Для
    продвинутых: -D и –I – это флаги
    препроцессора языка С. Подробнее о них можно почитать в справке или
    в любой книжке по С. Обратим наше внимание на то, что в
    традиционных компиляторах препроцессор и компилятор – это две
    разных программы, которые связываются пайпингом. В некоторых
    Renderman-совместимых рендерерах используется аналогичный подход,
    например, в BMRT и Aqsis. Есть такой препроцессор и у shader; его
    назвали slpp и спрятали в
    поддиректорию %{\it rmantree%\etc.}
  

 А как вы смотрите насчёт того, чтобы выстроить
    цепочку из нескольких программ-генераторов шейдеров? Или, например,
    написать внутри шейдера небольшую программу на Perl, затем
    обработать шейдер ещё одной небольшой программой на Perl – и
    получить таким образом динамически настраиваемый шейдер? А не
    изволите ли анимированных шейдеров? Возможностей – море, нужно
    только помнить, что вы ничего не можете сделать с самим шейдером {\it после} компиляции – только
    передать параметры из RIBа.

  \section*{txmake.exe}
  

 В этом случае всё совсем просто. Парадигма
    тотального ускорения рендеринга и разумного потребления памяти
    требует, чтобы всё, что поступало на вход рендерера, было
    максимально оптимизировано. Для RIBов таким вариантом является
    бинарный формат, для SL – откомпилированный код. Для текстур,
    которые вы можете использовать в своих шейдерах, тоже есть такой
    формат, и перевести текстуру в такой формат можно при помощи
    последней программы из нашей шустрой троицы –
    txmake.exe.
  

 Для
    продвинутых: Каким образом
    собственные форматы растровых текстур позволяют ускорить рендерер –
    и использовать более гигабайта текстур для одной модели? Всё очень
    просто:
  
     Текстура
      хранится не сплошным куском, а в виде тайлов – то есть побитой на
      квадратики. Соответственно, в память грузится не весь массив
      данных, а только тот квадратик, к которому идёт
      обращение.
     Внутри файла
      текстуры хранится не одно изображение, а несколько –
      последовательно уменьшающихся в размерах и детализации. Для
      объектов, нахожящихся на бОльшем расстоянии от камеры, используется
      текстура с меньшим разрешением – которая грузится быстрее и
      занимает меньше памяти.
     Прочие
      хитрости, вроде оптимизации данных под конкретный рендерер – так
      например prman при
      конвертации текстур может привести их размеры к величине, кратной
      степени двойки.
  
  

Таким
    образом, txmake при
    конвертации текстур создаёт многостраничный затайленый файл
    формата TIFF – благо
    формат позволяет. Просмотреть такой файл можно чем угодно,
    хоть ACDSee. Но если вы
    хотите воспользоваться текстурой размером в
    16000x16000 пикселей, а
    у вас на машине нет 2 гигабайт памяти – лучше использовать так
    называемый “старый” формат текстур Pixar, который
    можно получить при помощи того же txmake со
    специальными параметрами вызова – и который является ещё более
    оптимизированным вариантом.
  

 В Renderman Pro Server растровые изображения
    используются не только в качестве текстур, но и, например, как
    карты теней, если вы не пользуетесь рейтрейсингом. Обработка всех
    этих растров лежит на могучих плечах txmake.
  

 Одно небольшое отличие txmake от своих консольных
    собратьев состоит в том, что текстуры сами по себе текстовыми
    файлами не являются, то есть с ними наши фокусы с пайпингом
    работать не будут.
  

 Вот, собственно, и всё, что я хотел про неё
    рассказать. Ах, да, я забыл пример. Похулиганим
    немножко?
  

 По причинам, которые мы только что указали, пусть
    текстура будет квадратной, 512x512 пикселей. Напишем на ней...
    напишем на ней.... чего бы такого написать, чтобы никого не обидеть
    и чтобы литературный редактор пропустил? Вот, придумал:
  

 \gr{image055}
  

 Просто и со вкусом.
  

 Добавляем вызов текстуры в наш шейдер (по этому поводу переименованый в textured\_noise.sl):

\code{code/rib_example/textured_noise.sl}  


 Я несколько упростил наш шейдер по сравнению с
    последней итерацией (нам сейчас ни к чему все эти изыски с
    препроцессингом). Идея шейдера простая – показывается или надпись,
    или нойз (этакая модуляция нойза текстурой или, переходя на язык
    родных осин, перемножение двух изображений – очень распространённый
    приём).
  

 Для
    продвинутых: с педагогической точки
    зрения, код нашего шейдера следовало бы переписать несколько
    иначе:
  
\begin{lstlisting}[frame=single, framerule=0pt, framesep=10pt, xleftmargin=10pt, xrightmargin=10pt, basicstyle=\ttfamily \small, backgroundcolor=\color{light-gray}]
surface textured_noise ( float freq=100; )
{
  color tex = texture("texture.tif", s, t);
  float noi = noise(freq*s,freq*t);
  Ci  = tex * noi;
}
\end{lstlisting}
  

 В
    соответствии с рекомендуемым некоторыми источниками подходом,
    шейдеры необходимо разбивать на слои в соответствии с
    накладываемыми эффектами, и затем производить финальные операции
    уже над полученными ранее слоями. У этой модели есть свои
    преимущества и недостатки, сторонники и противники. Уточним лишь,
    что оптимизирующий компилятор шейдеров из комплекта {\it Renderman} {\it Pro} Server компилирует
    вышеприведённые шейдеры в почти одинаковый код.
  

Вносим также некоторые изменения в RIB:
  
\code{code/rib_example/test4.rib}

 Что мы сделали: исправили имя шейдера и немножко
    повернули наш шарик, чтобы надпись нормально читалась.
  

 Компилируем шейдер:
  
\begin{lstlisting}[frame=single, framerule=0pt, framesep=10pt, xleftmargin=10pt, xrightmargin=10pt, basicstyle=\ttfamily \small, backgroundcolor=\color{light-gray}]
shader textured_noise.sl
\end{lstlisting}
  

 Рендерим картинку:
  
\begin{lstlisting}[frame=single, framerule=0pt, framesep=10pt, xleftmargin=10pt, xrightmargin=10pt, basicstyle=\ttfamily \small, backgroundcolor=\color{light-gray}]
prman test4.rib
\end{lstlisting}

 и получаем огромное количество сообщений об
    ошибках, потому что рендерер не распознал нашу текстуру как
    правильный прооптимизированный формат. Строго говоря, какая-то
    картинка у нас получилась и так, но поскольку нас интересует
    академическая правильность процесса, то сделаем два дополнительных
    действия.
  

 Во-первых, подготовим картинку к
    рендерингу:
  

\begin{lstlisting}[frame=single, framerule=0pt, framesep=10pt, xleftmargin=10pt, xrightmargin=10pt, basicstyle=\ttfamily \small, backgroundcolor=\color{light-gray}]
txmake texture.tif texture.tx
\end{lstlisting}  

 То есть: берём нашу картинку и переводим её в новый
    формат, как водится, оптимизированный для рендеринга.
  

 Во-вторых, изменим шейдер:
  

\code{code/rib_example/textured_noise2.sl}  
  

 Для
    любознательных: Вас никто не
    заставляет называть свои файлы тем или иным образом. Вы можете
    хранить свой шейдеры в файлах с расширением *.shader; свою
    геометрию – в файлах с расширением *.rib, *.ri или *.renderman;
    инклуды в файлах *.h или *.inc. Просто стремитесь к тому, чтобы
    всегда придерживаться одного и того же логичного и удобного для вас
    именования файлов. Система именования, которую я использую в этой
    главе, считается стандартной и широко используется в литературе и
    документации.
  

 Для
    продвинутых: в процессе обработки
    текстур RAT включает в название файла параметры командной строки,
    которые использовались при вызове txmake. Например, вот так:
    metal024.tif.ppu.tx. Расшифровку скрытого в этом имени тайного
    значения оставим в качестве задания для самостоятельной работы для
    вас, продвинутые.
  

 Теперь вроде бы всё правильно – компилируем,
    запускаем рендерер и получаем в результате:

 \gr{image057}